﻿using System;
using System.Collections.Generic;
using System.Text;
using MigratorCore.Actions;
using MigratorCore;
using System.Collections.Specialized;
using MigratorCore.Status;
using MigratorCore.Objects;
using MigratorCore.Bases;
using System.Threading;
using System.Data.SqlClient;
using System.Data;
using System.Diagnostics;

namespace Migrator.CommunityServer.version2007_1
{
    public class UsersSource : ISourceAction

    {
        #region IAction Members

        private Settings settings;
        public Settings Settings
        {
            get
            {
                if (settings == null)
                {
                    settings = new Settings();
                    settings.Add("ConnectionString", "server=(localhost);uid=;pwd=;Trusted_Connection=yes;database=CommunityServer");
                    settings.Add("Import Profiles", false);
                }
                return settings;
            }
        }

        public string Name
        {
            get { return "Users Source"; }
        }

        private Status status;
        public MigratorCore.Status.Status Status
        {
            get
            {
                if (status == null)
                    status = new Status();
                return status;
            }
        }

        private ObjectSet objects;
        public MigratorCore.Objects.ObjectSet Objects
        {
            get
            {
                if (this.objects == null) this.objects = new ObjectSet();
                return this.objects;
            }
            set
            {
                this.objects = value;
            }
        }

        public MigratorCore.ActionType ActionType
        {
            get
            {
                return ActionType.Users;
            }
        }

        #endregion

        #region ISourceAction Members

        public void Get()
        {
            Debug.Listeners.Add(new TextWriterTraceListener(Console.Out));
            status.Completed = 0;
            status.AddEvent(new Event(EventType.Information, "Initializing", "Initializing Action", DateTime.Now));
            SqlDataReader sdr = null;
            SqlDataReader cdr = null;
            List<string> roles = new List<string>();
            List<string> roles2 = new List<string>();
            SqlConnection con = new SqlConnection(settings["ConnectionString"].ToString());
            SqlConnection con2 = new SqlConnection(settings["ConnectionString"].ToString());
            SqlConnection con3 = new SqlConnection(settings["ConnectionString"].ToString());
            int a = 0;

            #region Connection Commands
            try
            {
                string cmd2 = "SELECT count(cs_vw_Users_FullUser.Email) FROM cs_vw_Users_FullUser WHERE (cs_vw_Users_FullUser.IsAnonymous = 0)";
                string cmd = "";
                if (Boolean.Parse(settings["Import Profiles"].ToString()))
                    cmd = "SELECT cs_vw_Users_FullUser.UserName, cs_vw_Users_FullUser.Email, cs_vw_Users_FullUser.CreateDate, cs_vw_Users_FullUser.LastActivity, " +
                          "cs_vw_Users_FullUser.MembershipID, cs_vw_Users_FullUser.TimeZone, aspnet_Profile.PropertyNames, aspnet_Profile.PropertyValuesString " +
                          "FROM cs_vw_Users_FullUser LEFT OUTER JOIN aspnet_Profile ON aspnet_Profile.UserId = cs_vw_Users_FullUser.MembershipID WHERE (cs_vw_Users_FullUser.IsAnonymous = 0)";
                else cmd = "SELECT cs_vw_Users_FullUser.UserName, cs_vw_Users_FullUser.Email, cs_vw_Users_FullUser.CreateDate, cs_vw_Users_FullUser.LastActivity, " +
                           "cs_vw_Users_FullUser.MembershipID, cs_vw_Users_FullUser.TimeZone " +
                           "FROM cs_vw_Users_FullUser WHERE (cs_vw_Users_FullUser.IsAnonymous = 0)";
                SqlCommand sc = new SqlCommand(cmd2, con);
                con.Open();
                a = int.Parse(sc.ExecuteScalar().ToString());
                con.Close();
                sc = new SqlCommand(cmd, con2);
                con2.Open();
                sdr = sc.ExecuteReader();
                //Load All Roles from Database
                cmd = "SELECT aspnet_Roles.RoleName, aspnet_UsersInRoles.UserId FROM aspnet_UsersInRoles INNER JOIN aspnet_Roles ON aspnet_UsersInRoles.RoleId = aspnet_Roles.RoleId";
                sc = new SqlCommand(cmd, con3);
                con3.Open();
                cdr = sc.ExecuteReader();
            }
            catch (Exception e)
            {
                status.Completed = 100;
                status.AddEvent(new Event(EventType.CriticalError, "Data Connection Failed!", e.Message, e, DateTime.Now));
                return;
            }
            #endregion
            int x = 0;
            #region Role Parsing
            status.AddEvent(new Event(EventType.Information, "Loading Role Database", "Loaded Role Database", DateTime.Now));
            while (cdr.Read())
            {
                x++;
                roles.Add(cdr.GetGuid(1).ToString());
                roles2.Add(cdr.GetString(0));

            }
            con3.Close();
            status.Completed = 1;
            status.AddEvent(new Event(EventType.Information, "Loaded " + x.ToString() + " users in roles", "Loaded Role Database", DateTime.Now));
            #endregion
            if (sdr == null) { status.Completed = 100; status.AddEvent(new Event(EventType.CriticalError, "Database Connection Failed", "SQL Command Execution Failed", DateTime.Now)); return; }           
            status.AddEvent(new Event(EventType.Information, "Loaded " + a + " Users from the Database", "Loaded " + a + " users from the source database, starting processing", DateTime.Now));
            x=0;
            while (sdr.Read())
            {
                x++;
                User user = new User(sdr.GetString(0), sdr.GetString(1));
                try
                {
                    user.Datelastvisited = sdr.GetDateTime(3);
                    user.Datejoined = sdr.GetDateTime(2);
                    user.EnableEmail = true;
                    user.Timezone = int.Parse(sdr.GetValue(5).ToString());
                    try
                    {
                        #region Profile Parsing
                        if (Boolean.Parse(settings["Import Profiles"].ToString()))
                        {
                            if (string.IsNullOrEmpty(sdr.GetString(6)) || string.IsNullOrEmpty(sdr.GetString(7)))
                            {
                                status.AddEvent(new Event(EventType.MissingData, "Profile Data is Missing", "The Profile Data is Missing", DateTime.Now));
                            }
                            else user.Attributes = Serializer.ConvertToNameValueCollection(sdr.GetString(6), sdr.GetString(7));
                        }
                        #endregion
                    }
                    catch (Exception e)
                    {
                        status.AddEvent(new Event(EventType.MissingData, "Missing Profile Data", e.Message, e, DateTime.Now));
                    }
                    try
                    {
                        user.Roles = new List<string>();
                        for (int i = 0; i < roles.Count; i++)
                            if (roles[i] == sdr.GetGuid(4).ToString())
                                user.Roles.Add(roles2[i]);
                    }
                    catch (Exception e)
                    {
                        status.AddEvent(new Event(EventType.MissingData, "Missing Role Data", e.Message, e, DateTime.Now));
                    }
                    this.Objects.Add(user);
                    double aa = 0.00 + a;
                    string s = (Boolean.Parse(settings["Import Profiles"].ToString())) ? " With Profile" : "";
                    status.Completed = Convert.ToInt32(Math.Round(Convert.ToDecimal(((x + 1) / aa) * 100), 0));
                    status.AddEvent(new Event(EventType.Information, "Processed User " + sdr.GetString(0) + " " + s, "Processed user " + sdr.GetString(0) + " " + s, DateTime.Now));
                }
                catch (Exception e)
                {
                    double aa = 0.00 + a;
                    status.Completed = Convert.ToInt32(Math.Round(Convert.ToDecimal(((x + 1) / aa) * 100), 0));
                    status.AddEvent(new Event(EventType.MissingData, "Unable to import user " + user.Name + ", skipping", e.Message, e, DateTime.Now));
                }
            }
            con2.Close(); con2.Dispose();
        }

        #endregion
    }
}
